#include "hardware.h"
#include "app_functions.h"
#include "protocal.h"
#include "timer.h"


/******************/
//硬件相关全局变量定义
acpower_t 		gst_acpower 	= {0};
load_t 			gst_load 		= {0};
battery_t 		gst_battery 	= {0};
charger_t 		gst_charger		= {0};
com_type_t 		gst_com_type 	= {0};

float 			gf_vmcu 		= 5.0;					//VDD电压值，默认5V
uint8_t 		gu8_tiger_flag 	= 0;					//备电按键状态
uint8_t  		gu8_detect_count = 0;					//检测函数的执行时序
uint16_t 		gu16_detect_done = 0xffff;				//检测函数执行完成状态
uint8_t  		gu8_output_power_flag = MAIN_OUT;		//gu8_output_power_flag 指示电源主备电状态，  		MAIN_OUT：主电，BAT_OUT：备电；
uint8_t			gu8_bat_type_flag = LEAD_ACID;			//gu8_bat_type_flag 指示电池类型 LEAD_ACID：铅酸电池，LI_ION：磷酸铁锂电池
uint8_t			gu8_soft_wdg_clear_flag = 0;			//喂狗标志位，目前是等待所有关键检测处理函数都执行后喂狗
uint8_t  		gu8_detect_bat_lost_flag = 0;			//检测电池丢失标志位
uint8_t  		gu8_get_real_vbat_flag = 0;				//获取电池端口有效电压标志位，目前在应用检测到端口过压时
int8_t          gs8_calib_ac_value = 0;					//校准AC电压值
uint8_t  		gu8_detect_battery_resistance_flag = 0;	//检测电池内阻标志位
uint8_t 		gu8_check_battery_resistance_time = 0;	//内阻检测时间，单位为分钟
uint16_t 		gu16_check_battery_resistance_ms = 0;	//内阻检测时间，单位为毫秒
uint16_t 		gu16_battery_res_timer = 0;				//用于内阻检测的长时间定时计数器

uint16_t		gu16_ac_ad_value[ac_detect_count] = {0};
uint8_t        	gu8_ac_detect_done = 0;

/******************/

void set_dacu_volatage_of_temperature(float temp)
{
	/**
	vol = -0.003*12*(temp-20)+27.3
	*/
	float vol = (float)(-0.003 * 12 * (temp - 20) + 27.3); 
	gst_charger.dac_volatge = (uint16_t)(vol * 100 + 0.5);
	uint8_t ad = DACU_VOLATAGE(vol);
	if (ad < 141)
	{
		ad = 141;
	}
	else if (ad > 152)
	{
		ad = 152;
	}
	setDACU(ad);
}

//等待的方式发送
void Uart_Host_Loop_Write(const uint8_t *p_buffer, uint8_t u8_len)
{
	uint8_t i;

#if CHECK_HOST_485_EN > 0	
	HOST_485_TX_EN();
#endif
	for(i=0;i<u8_len;i++)
	{
		USART0_Write(*(p_buffer+i));
		while(!(USART0.STATUS & USART_TXCIF_bm));
	}
#if CHECK_HOST_485_EN > 0
	HOST_485_RX_EN();
#endif
}

//中断的方式发送
void Uart_Host_Write(const uint8_t *p_buffer, uint8_t u8_len)
{
	uint8_t i;
	if (u8_len > USART_BUFFER_SIZE)
	{
		//printf("data len too long!");
		return;
	}
	if (p_buffer == NULL)
	{
		//printf("buffer invalid!");
		return;
	}
	for (i=0; i<(u8_len); i++)
    {
        gu8_uart_host_tx_buf[gu8_uart_host_tx_trace++] = *(p_buffer+i);
		if (gu8_uart_host_tx_trace >= USART_BUFFER_SIZE)
		{
			gu8_uart_host_tx_trace = 0;
		}
    }
	DISABLE_INTERRUPTS();
	gu8_uart_host_tx_remain += u8_len;
	ENABLE_INTERRUPTS();
	
#if CHECK_HOST_485_EN > 0
	HOST_485_TX_EN();
	USART0.CTRLA |= USART_DREIE_bm|USART_TXCIE_bm; 
#else
	USART0.CTRLA |= USART_DREIE_bm; 
#endif
}

/**
 * @brief handler_deal_recv_data
 *          在接收中断对收到的数据验证CRC
 * @param r_data 待处理数据
 * @return void
 info 适用于没有串口空闲中断的MCU模块，在需要及时处理数据时使用
 */

void handler_deal_recv_data(uint8_t dat)
{
	static uint8_t *u8p = NULL, u8Com_Step = 0, u8escape = 0;	//u8Com_Step标识解析步骤
	uint8_t u8Data = 0, k;						
	

	u8Data = dat;												//取出数据
	
	switch (u8Com_Step)				
	{
		case 0:										
			if (u8Data == PROTOCAL_START_FLAG)					//发现帧头
			{
				u8p = gu8_uart_host_rx_buf;
				gu8_uart_host_rx_remain = 0;
				u8Com_Step = 1;
			}
			else
			{
				u8Com_Step = 0;
				u8p = NULL;
			}
		break;
		
		case 1:	
			//发现帧头后紧接着的数据不是结束标志，认为帧有效
			if (u8Data != PROTOCAL_END_FLAG && (u8p-gu8_uart_host_rx_buf) < USART_BUFFER_SIZE)		
			{
				if (u8Data == PROTOCAL_ESCAPE_FLAG)
				{
					u8escape = 1;
					return;
				}
				if (u8escape == 1)
				{
					if (u8Data == 0x5E)
					{
						*u8p++ = 0x7E;
					}
					else if (u8Data == 0x5D)
					{
						*u8p++ = 0x7D;
					}
					else
					{
						u8Com_Step = 0;
						u8p = NULL;
					}
					u8escape = 0;
					gu8_uart_host_rx_remain++;
				}
				else
				{
					*u8p++ = u8Data;
					gu8_uart_host_rx_remain++;
				}
				
			}	
			else									//转义结束，或者收到其他异常，下一步开始校验、处理数据
			{
				if ((u8Data == PROTOCAL_END_FLAG) && ((u8p-gu8_uart_host_rx_buf) > 2))	//是有效帧
				{
					//主机下发指令，地址是本机或广播，可以继续下一步响应
					if ((gu8_uart_host_rx_buf[0] == PROTOCAL_SLAVE_ADDR || gu8_uart_host_rx_buf[0] == 0xFF)
						&& ((gu8_uart_host_rx_buf[1]&0x01) == 0))										
					{
						//挂载到缓存池，如果当前缓存池满，丢弃最新数据，后续等待主机重发
						for (k=0;k<uart_msg_rec_buffer_num;k++)
						{
							if (gst_uart_msg_rec[k].u8is_used == NO)
							{
								gst_uart_msg_rec[k].u8is_used = YES;
								gst_uart_msg_rec[k].u8len = gu8_uart_host_rx_remain;
								if (gst_uart_msg_rec[k].u8len <= sizeof(gst_uart_msg_rec[k].msg))		//有效大小，保存
								{
									memcpy(gst_uart_msg_rec[k].msg, gu8_uart_host_rx_buf, gst_uart_msg_rec[k].u8len);
								}
								else
								{
									gst_uart_msg_rec[k].u8is_used = NO;
								}
								
								break;
							}
						}

						if ((gu8_uarthostRxStatusFlag & 0x02) == 0)		//标识uart0开始接收一帧本机数据，开始等待总线空闲
						{
							gu8_uarthostRxStatusFlag |= 0x02;
						}
						u8Com_Step = 0;
						u8p = NULL;
					}
					else							//不是本机地址，不理会
					{
						u8Com_Step = 0;
						u8p = NULL;						
					}
				}
				else if ((u8Data == PROTOCAL_END_FLAG) && (u8p == gu8_uart_host_rx_buf))
				{
					u8p = gu8_uart_host_rx_buf;
					gu8_uart_host_rx_remain = 0;
					u8Com_Step = 1;
				}
				else
				{
					u8Com_Step = 0;
					u8p = NULL;
				}
			}
		break;

		default:
			u8Com_Step = 0;
			u8p = NULL;
		break;
	}
}

void UART_HOST_RxIsrCb(void)
{
    uint8_t u8_data;

    /* Read the received data */
    u8_data = USART0.RXDATAL;

   	handler_deal_recv_data(u8_data);
	
	
	if ((gu8_uarthostRxStatusFlag & 0x02) != 0 && (gu8_uarthostRxStatusFlag & 0x04) != 0)
	{
		gu8_uarthostRxStatusFlag &= 0xFB;			//清除接收结束标志位-bit2，该标志在定时器中断置位，用于判断接收是否完毕
	}
}

void UART_HOST_TxIsrCb(void)
{
    /* Check if all data is transmitted */
    if (gu8_uart_host_tx_remain != 0) {
        /* Calculate buffer index */
       	if (gu8_uart_host_tx_index >= USART_BUFFER_SIZE)
       	{
        	gu8_uart_host_tx_index = 0;
       	}
        /* Start transmission */
        USART0.TXDATAL = gu8_uart_host_tx_buf[gu8_uart_host_tx_index++];

        gu8_uart_host_tx_remain--;
    }
   	if (gu8_uart_host_tx_remain == 0)
	{
        /* Disable Tx interrupt */
        USART0.CTRLA &= ~USART_DREIE_bm;
		if (gu8_uart_host_tx_index != gu8_uart_host_tx_trace)
		{
			gu8_uart_host_tx_index = gu8_uart_host_tx_trace;
		}
    }
}

/******************/
//全局变量初始化功能函数
//参数: void
//返回: void
/******************/
static void Init_Global_Data(void)
{	
	gu8_tiger_flag = 0;
	gu8_detect_count = 0;
	gu16_detect_done = 0xffff;
	gu8_output_power_flag = BAT_OUT;
	gu8_bat_type_flag = LEAD_ACID;
	gu8_soft_wdg_clear_flag = 0;
	gu8_detect_bat_lost_flag = NO;
	gu8_detect_battery_resistance_flag = NO;
	gu8_get_real_vbat_flag = NO;
	gu8_check_battery_resistance_time = TIMER_CHECK_BATTERY_RESISTANCE_MIN;		//10min
	gu16_check_battery_resistance_ms   = TIMER_CHECK_BATTERY_RESISTANCE_MS;		//60S

	Protocal_Init();															//初始化通讯相关变量

	//获取最新的5V校准值
	gf_vmcu = ((FLASH_READ_BYTE(FLASH_S_ADDR+0x03)<<8) + FLASH_READ_BYTE(FLASH_S_ADDR+0x04)) / 1000.0;
	if (gf_vmcu < 4.80 || gf_vmcu > 5.20)										//超过精度范围
	{
		gf_vmcu = 5.000;
	}
	//获取最新的AC电压校准值
	gs8_calib_ac_value = (int8_t)(FLASH_READ_BYTE(FLASH_S_ADDR+0x02));
	if (gs8_calib_ac_value < -15 || gs8_calib_ac_value > 15)					//超过认可的补偿范围，此处是采样误差范围
	{
		gs8_calib_ac_value = 0;
	}
	#ifdef debug_f
		u6_debug_value = (FLASH_READ_BYTE(FLASH_S_ADDR+0x03)<<8) + FLASH_READ_BYTE(FLASH_S_ADDR+0x04);
	#endif
	flag_operation(&(gst_charger.CHARGER_FLAG_STATUS), SET, STATE);				//置位停止充电标志位

	SET_TIMER_MS(TIMER_CHECK_SYS_STATE, TIMER_DELAY_2S);  						//定时2S，初始化后数据采集完成上传一次
}

/******************/
//初始化IO功能函数
//参数: void;
//返回: -1：IO初始化异常
//		 0：IO初始化正常
/******************/
static int8_t IO_Init(void)
{	
	CHARGER_OFF();					//关闭充电开关
	BATOFF_OFF();					//关闭备电输出
	MAINOFF_ON();					//打开主电
#if CHECK_BAT_LIION_EN > 0
	SWITCH_LIION_OFF();				//默认适配铅酸电池充电器电压
#endif
	BAT_LOSS_D_OFF();				//关电池丢失测试开关
	SCP_TEST_OFF();					//关短路测试开关

	//读取IO相关寄存器设置是否成功
	if (VPORTA_DIR != 0xE0 || VPORTB_DIR != 0x85 || VPORTC_DIR != 0x11)	
	{
		return -1;
	}
	
	PORTB_PIN5CTRL = 0x03;    					//在此处开启短路中断开关
	
	return 0;
}


/******************/
//EEPROM初始化功能函数
//参数: void;
//返回: -1：EEPROM 异常
//		 0：EEPROM 正常
/******************/
static int8_t Eeprom_Init(void)
{
	uint16_t u16_eeprom_test_addr = FLASH_S_ADDR;
	uint8_t u8_write_test_data[10] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};	//测试数据
	uint8_t u8_read_test_data[10], u8_save_data[10], i;
	
	
	FLASH_READ_ARRAY(u16_eeprom_test_addr, u8_save_data, sizeof(u8_save_data));						//保存以前存在的数据
	FLASH_WRITE_ARRAY(u16_eeprom_test_addr, u8_write_test_data, sizeof(u8_write_test_data));		//EEPROM写入数据
	
	FLASH_READ_ARRAY(u16_eeprom_test_addr, u8_read_test_data, sizeof(u8_read_test_data));			//回读刚才写入的数据，因为使用的字节数有限，初始化就只验证这几个位置是否正常
	for (i=0; i<10; i++)
	{
		if (u8_read_test_data[i] != u8_write_test_data[i])
		{
			FLASH_WRITE_ARRAY(u16_eeprom_test_addr, u8_save_data, sizeof(u8_save_data));
			return -1;
		}
	}
	
	FLASH_WRITE_ARRAY(u16_eeprom_test_addr, u8_save_data, sizeof(u8_save_data));					//还原以前的数据
	return 0;
}

/******************/
//输出短路测试功能函数
//参数: void;
//返回: -1：输出短路
//		 0：输出正常
/******************/
static int8_t Output_Scp_Test(void)
{
	uint16_t u16_Short_Test_AD_Value = 0, k;
	
	BATOFF_OFF();
	SCP_TEST_ON();
	DELAY_MS(550);										//该时间直接影响带载能力，一定程度上时间越长带载越强
	for(k = 0; k < 5; k++)
	{
		u16_Short_Test_AD_Value += getADC1(V_OUT);
		DELAY_MS(10);
	}
	SCP_TEST_OFF();
	
	if ((u16_Short_Test_AD_Value/k) < THRESHOLD_V(0.5))	//VOUT < 0.5V判断输出短路
	{
		flag_operation(&(gst_load.LOAD_FLAG_CURRENT_SHORT), SET, ACTION_BATOFF);
		return -1;
	}
	return 0;
}

/******************/
//开机电池电压检测功能函数
//参数: void;
//返回: void;
//tip:当备电开机时检测到电池电压低于21V则没必要开机
/******************/
static void BAT_Init_Lost_Test(void)
{
	uint16_t u16_AD_Value = 0, k;
	
	BAT_LOSS_D_ON();
	DELAY_MS(300);	
	k = 3;
	u16_AD_Value = 0;
	while(k > 0)
	{
		u16_AD_Value += getADC0(BAT);
		DELAY_MS(10);
		k--;
	}
	BAT_LOSS_D_OFF();							//先采样再关泄放回路

	u16_AD_Value /= 3;							//取均值
	if (u16_AD_Value < THRESHOLD_V(15))			//计算宏，电池电压小于15V判定为电池丢失
	{
		//判定为电池丢失，电池相关标志位默认还是清除状态
		flag_operation(&(gst_battery.BATTERY_FLAG_LOST), SET, STATE|ACTION_CHARGEROFF);				
	}
	else
	{
		//电池存在	
		flag_operation(&(gst_battery.BATTERY_FLAG_LOST), CLEAR, STATE|ACTION_CHARGEROFF);
	}
	
	if (u16_AD_Value < THRESHOLD_V(21))			//电池电压过低，不开机
	{
		flag_operation(&(gst_battery.BATTERY_FLAG_VOLTAGE_LOW), SET, ACTION_BATOFF);
	}
}


/******************/
//硬件初始化功能函数
//参数:    void
//返回:    0：硬件初始化正常
//       1：IO寄存器初始化失败
//       2：EEPROM初始化失败
//       3：输出短路
/******************/
uint8_t Hardware_Init(void)
{	
	uint8_t u8_sys_error_code = 0;				//系统状态错误码

	if (IO_Init() != 0)
	{
		u8_sys_error_code = 1;
		return u8_sys_error_code;
	}

	if (Eeprom_Init() != 0)
	{
		u8_sys_error_code = 2;
		return u8_sys_error_code;
	}
	
	Init_Global_Data();							//初始化变量，包括VCC电压

	BAT_Init_Lost_Test();						//是否电池丢失或欠压
	if (Output_Scp_Test() != 0)					//输出状态探测
	{
		u8_sys_error_code = 3;					//即使输出短路，系统也可继续运行
	}

	CLEAR_TIMERBASE_INTFLAG();					//清除时基定时器中断标志位
	TIMERBASE_INTERRUPT_ENABLE();				//开启时基定时器计时中断		
	UART_HOST_INTERRUPT_ENABLE();				//开启主机串口通讯接收中断-USART0		
	TIMER_CAP_INTERRUPT_ENABLE();				//开启AC检测定时器中断
	INTERRUPT_GLOBAL_ENABLE();					//开启全局中断
	
	return u8_sys_error_code;
}

/******************/
//开机软起动功能函数
//参数: void;
//返回: void;
/******************/
void Soft_Start(void)
{
	uint8_t  u8_cycle;
	uint16_t u16_count, k;
	
	for (k = 0; k<=100; k++)			//软启动周期800us, 101*10次，约0.8S
	{
		u8_cycle = 10;
		while(u8_cycle > 0)				//每个周期10次
		{
			if ((u8_cycle == 1) && k >= 30)			//
			{
				if (getADC1(V_OUT) < 10)			//THRESHOLD_V(0.5),约为0.53V，0.53/11/5*1024
				{
					BATOFF_OFF();
					flag_operation(&(gst_load.LOAD_FLAG_CURRENT_SHORT), SET, ACTION_BATOFF);
				}
			}
			u16_count = (k);			
			while (u16_count--)
			{
				if ((gst_load.LOAD_FLAG_CURRENT_SHORT & ACTION_BATOFF) == 0)
				{
					BATOFF_ON();
				}
				//1us
				DELAY_US(1);
			}
			
			BATOFF_OFF();
			u16_count = (800-k);
			while (u16_count--)
			{
				//1us
				DELAY_US(1);
			}
			u8_cycle--;
		}
	}
	if ((getADC1(V_OUT) > THRESHOLD_V(15.0)) && ((gst_load.LOAD_FLAG_CURRENT_SHORT & ACTION_BATOFF) == 0))
	{
		BATOFF_ON();
	}
	else
	{
		BATOFF_OFF();
		flag_operation(&(gst_load.LOAD_FLAG_CURRENT_SHORT), SET, ACTION_BATOFF);
	}
}


void SCP_HandleIsrCb(void)
{
	uint8_t i = 0;
	
	if (SCP_IO_STATE() == 0)
	{
		//DELAY_US(10);
		if (getADC1(I_OUT) > THRESHOLD_I_SHORT_80A)
		{
			i++;
		}
		if (getADC1(I_OUT) > THRESHOLD_I_SHORT_80A)
		{
			i++;
		}
		/*if (getADC1(I_OUT) > THRESHOLD_I_SHORT_80A)
		{
			i++;
		}*/
		if (i >= 2)
		{
			BATOFF_OFF();
			gst_load.LOAD_FLAG_CURRENT_SHORT |= ACTION_BATOFF|ACTION_CHARGEROFF;
		}

		if (getADC1(V_OUT) < THRESHOLD_V_SHORT_25V)
		{
			BATOFF_OFF();
			gst_load.LOAD_FLAG_CURRENT_SHORT |= ACTION_BATOFF|ACTION_CHARGEROFF;
		}
	}
}

